package dingding;

import com.aliyun.dingtalkoauth2_1_0.models.GetCorpAccessTokenRequest;
import com.aliyun.dingtalkoauth2_1_0.models.GetCorpAccessTokenResponse;
import com.aliyun.dingtalkstorage_1_0.models.CommitFileHeaders;
import com.aliyun.dingtalkstorage_1_0.models.CommitFileRequest;
import com.aliyun.dingtalkstorage_1_0.models.CommitFileResponse;
import com.aliyun.dingtalkstorage_1_0.models.CommitFileResponseBody;
import com.aliyun.dingtalkstorage_1_0.models.GetFileUploadInfoHeaders;
import com.aliyun.dingtalkstorage_1_0.models.GetFileUploadInfoRequest;
import com.aliyun.dingtalkstorage_1_0.models.GetFileUploadInfoResponse;
import com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceHeaders;
import com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceRequest;
import com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceResponse;
import com.aliyun.dingtalkworkflow_1_0.models.GetProcessInstanceResponseBody;
import com.aliyun.dingtalkworkflow_1_0.models.QuerySchemaByProcessCodeHeaders;
import com.aliyun.dingtalkworkflow_1_0.models.QuerySchemaByProcessCodeRequest;
import com.aliyun.dingtalkworkflow_1_0.models.QuerySchemaByProcessCodeResponse;
import com.aliyun.dingtalkworkflow_1_0.models.QuerySchemaByProcessCodeResponseBody;
import com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceHeaders;
import com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceRequest;
import com.aliyun.dingtalkworkflow_1_0.models.StartProcessInstanceResponse;
import com.aliyun.tea.TeaException;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import exception.CodeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

/**
 * @author zhanglinfeng
 * @date create in 2024/2/29 17:59
 */
public class DingDingUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(DingDingUtil.class);

    /**
     *
     * @param authCorpId
     * @param customKey
     * @param customSecret
     * @param processCode
     * @return
     */
    public static List<QuerySchemaByProcessCodeResponseBody.QuerySchemaByProcessCodeResponseBodyResultSchemaContentItems> getApprovalTemplate(String authCorpId, String customKey, String customSecret, String processCode) {
        QuerySchemaByProcessCodeHeaders headers = new QuerySchemaByProcessCodeHeaders();
        headers.xAcsDingtalkAccessToken = getToken(authCorpId, customKey, customSecret);
        QuerySchemaByProcessCodeRequest request = new QuerySchemaByProcessCodeRequest().setProcessCode(processCode);
        try {
            QuerySchemaByProcessCodeResponse response = new com.aliyun.dingtalkworkflow_1_0.Client(getConfig()).querySchemaByProcessCodeWithOptions(request, headers, new RuntimeOptions());
            if (200 == response.statusCode) {
                return response.body.result.schemaContent.items;
            }
            if (400 == response.statusCode) {
                throw new CodeException("PLEASE CHECK THE TEMPLATE CODE", "模板信息获取失败，请检查模板编码");
            }
            LOGGER.error("获取钉钉审批表单模板失败，code{}", response.statusCode);
            throw new CodeException("REQUEST DINGDING EXCEPTION", "调用钉钉服务出错，请联系管理员");
        } catch (TeaException e) {
            LOGGER.error("获取钉钉审批表单模板异常TeaException : ", e);
            throw new CodeException("REQUEST DINGDING EXCEPTION", "调用钉钉服务出错，请联系管理员");
        } catch (Exception e) {
            LOGGER.error("获取钉钉审批表单模板异常Exception : ", e);
            throw new CodeException("REQUEST DINGDING EXCEPTION", "调用钉钉服务出错，请联系管理员");
        }
    }

    public static String createApprovalInstance(String authCorpId, String customKey, String customSecret, String originatorUserId, Long deptId, String processCode, List<StartProcessInstanceRequest.StartProcessInstanceRequestFormComponentValues> valuesList) {
        StartProcessInstanceHeaders headers = new StartProcessInstanceHeaders();
        headers.xAcsDingtalkAccessToken = getToken(authCorpId, customKey, customSecret);
        StartProcessInstanceRequest request = new StartProcessInstanceRequest()
                .setOriginatorUserId(originatorUserId)
                .setProcessCode(processCode)
                .setDeptId(deptId)
                .setFormComponentValues(valuesList);
        try {
            StartProcessInstanceResponse response = new com.aliyun.dingtalkworkflow_1_0.Client(getConfig()).startProcessInstanceWithOptions(request, headers, new RuntimeOptions());
            if (200 == response.statusCode) {
                return response.body.instanceId;
            }
            LOGGER.error("新建钉钉审批实例失败，code{}", response.statusCode);
            throw new CodeException("REQUEST DINGDING EXCEPTION", "调用钉钉服务出错，请联系管理员");
        } catch (TeaException e) {
            LOGGER.error("新建钉钉审批实例异常TeaException : ", e);
            throw new CodeException("REQUEST DINGDING EXCEPTION", "调用钉钉服务出错，请联系管理员");
        } catch (Exception e) {
            LOGGER.error("新建钉钉审批实例异常Exception : ", e);
            throw new CodeException("REQUEST DINGDING EXCEPTION", "调用钉钉服务出错，请联系管理员");
        }
    }

    public static List<GetProcessInstanceResponseBody.GetProcessInstanceResponseBodyResultOperationRecords> getApprovalInstanceDetail(String authCorpId, String customKey, String customSecret, String processInstanceId) {
        GetProcessInstanceHeaders headers = new GetProcessInstanceHeaders();
        headers.xAcsDingtalkAccessToken = getToken(authCorpId, customKey, customSecret);
        GetProcessInstanceRequest request = new GetProcessInstanceRequest().setProcessInstanceId(processInstanceId);
        try {
            GetProcessInstanceResponse response = new com.aliyun.dingtalkworkflow_1_0.Client(getConfig()).getProcessInstanceWithOptions(request, headers, new RuntimeOptions());
            if (200 == response.statusCode) {
                return response.body.result.operationRecords;
            }
            throw new CodeException("REQUEST DINGDING EXCEPTION", "调用钉钉服务出错，请联系管理员");
        } catch (TeaException e) {
            LOGGER.error("获取钉钉单个审批实例详情异常TeaException : ", e);
            throw new CodeException("REQUEST DINGDING EXCEPTION", "调用钉钉服务出错，请联系管理员");
        } catch (Exception e) {
            LOGGER.error("获取钉钉单个审批实例详情异常Exception : ", e);
            throw new CodeException("REQUEST DINGDING EXCEPTION", "调用钉钉服务出错，请联系管理员");
        }
    }

    public static CommitFileResponseBody.CommitFileResponseBodyDentry uploadFile(String authCorpId, String customKey, String customSecret, String unionId, String spaceId, String parentId, InputStream is, String fileName) {
        String uploadKey = null;
        //获取token
        String token = getToken(authCorpId, customKey, customSecret);
        //加接口权限，加人员的钉盘权限
        //步骤一：获取上传文件需要的resourceUrls和headers参数值。
        String resourceUrl = null;
        Map<String, String> headers = null;
        GetFileUploadInfoHeaders getFileUploadInfoHeaders = new GetFileUploadInfoHeaders();
        getFileUploadInfoHeaders.xAcsDingtalkAccessToken = token;
        GetFileUploadInfoRequest getFileUploadInfoRequest = new GetFileUploadInfoRequest()
                .setUnionId(unionId)
                .setProtocol("HEADER_SIGNATURE")
                .setMultipart(false);
        try {
            GetFileUploadInfoResponse response = new com.aliyun.dingtalkstorage_1_0.Client(getConfig()).getFileUploadInfoWithOptions(spaceId, getFileUploadInfoRequest, getFileUploadInfoHeaders, new com.aliyun.teautil.models.RuntimeOptions());
            uploadKey = response.body.uploadKey;
            resourceUrl = response.body.headerSignatureInfo.resourceUrls.get(0);
            headers = response.body.headerSignatureInfo.headers;
        } catch (TeaException e) {
            LOGGER.error("上传文件到钉盘,步骤一异常TeaException : ", e);
            throw new CodeException("REQUEST DINGDING EXCEPTION", "调用钉钉服务出错，请联系管理员");
        } catch (Exception e) {
            LOGGER.error("上传文件到钉盘,步骤一异常Exception ：", e);
            throw new CodeException("REQUEST DINGDING EXCEPTION", "调用钉钉服务出错，请联系管理员");
        }
        //步骤二：使用OSS的header加签方式上传文件
        try {
            URL url = new URL(resourceUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            if (headers != null) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    connection.setRequestProperty(entry.getKey(), entry.getValue());
                }
            }
            connection.setDoOutput(true);
            connection.setRequestMethod("PUT");
            connection.setUseCaches(false);
            connection.setReadTimeout(10000);
            connection.setConnectTimeout(10000);
            connection.connect();
            OutputStream out = connection.getOutputStream();
            byte[] b = new byte[1024];
            int temp;
            while ((temp = is.read(b)) != -1) {
                out.write(b, 0, temp);
            }
            out.flush();
            out.close();
            int responseCode = connection.getResponseCode();
            String message = connection.getResponseMessage();
            connection.disconnect();
            if (responseCode != 200) {
                LOGGER.error("上传文件到钉盘,步骤二失败，responseCode：{},message:{}", responseCode, message);
                throw new CodeException("REQUEST DINGDING EXCEPTION", "调用钉钉服务出错，请联系管理员");
            }
        } catch (Exception e) {
            LOGGER.error("上传文件到钉盘,步骤二异常Exception ：", e);
            throw new CodeException("REQUEST DINGDING EXCEPTION", "调用钉钉服务出错，请联系管理员");
        }
        //步骤三：调用提交文件接口，完成文件上传。
        CommitFileHeaders commitFileHeaders = new CommitFileHeaders();
        commitFileHeaders.xAcsDingtalkAccessToken = token;
        CommitFileRequest.CommitFileRequestOption option = new CommitFileRequest.CommitFileRequestOption().setConflictStrategy("AUTO_RENAME");
        CommitFileRequest commitFileRequest = new CommitFileRequest()
                .setUnionId(unionId)
                .setUploadKey(uploadKey)
                .setName(fileName)
                .setParentId(parentId)
                .setOption(option);
        try {
            CommitFileResponse response = new com.aliyun.dingtalkstorage_1_0.Client(getConfig()).commitFileWithOptions(spaceId, commitFileRequest, commitFileHeaders, new com.aliyun.teautil.models.RuntimeOptions());
            return response.body.dentry;
        } catch (TeaException e) {
            LOGGER.error("上传文件到钉盘,步骤三异常TeaException : ", e);
            throw new CodeException("REQUEST DINGDING EXCEPTION", "调用钉钉服务出错，请联系管理员");
        } catch (Exception e) {
            LOGGER.error("上传文件到钉盘,步骤三异常Exception ：", e);
            throw new CodeException("REQUEST DINGDING EXCEPTION", "调用钉钉服务出错，请联系管理员");
        }
    }

    private static Config getConfig() {
        Config config = new Config();
        config.protocol = "https";
        config.regionId = "central";
        return config;
    }

    protected static String getToken(String authCorpId, String customKey, String customSecret) {
        GetCorpAccessTokenRequest getCorpAccessTokenRequest = new GetCorpAccessTokenRequest()
                .setSuiteKey(customKey)
                .setSuiteSecret(customSecret)
                .setAuthCorpId(authCorpId)
                .setSuiteTicket(String.valueOf(LocalDateTime.now().getSecond()));
        try {
            GetCorpAccessTokenResponse response = new com.aliyun.dingtalkoauth2_1_0.Client(getConfig()).getCorpAccessToken(getCorpAccessTokenRequest);
            return response.getBody().getAccessToken();
        } catch (TeaException e) {
            LOGGER.error("获取钉钉accessToken异常TeaException : ", e);
            throw new CodeException("REQUEST DINGDING EXCEPTION", "调用钉钉服务出错，请联系管理员");
        } catch (Exception e) {
            LOGGER.error("获取钉钉accessToken异常Exception : ", e);
            throw new CodeException("REQUEST DINGDING EXCEPTION", "调用钉钉服务出错，请联系管理员");
        }
    }
}
